package com.itheima.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.BaseContext;
import com.itheima.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// 在这里如果不配置 默认拦截的是 所有资源....
@WebFilter(filterName = "LoginCheckFilter")
@Slf4j
public class LoginCheckFilter implements Filter {


    /**
     *  过滤器的逻辑是什么呢?
     *     什么样的资源 放行
     *     什么样的资源 不放行
     */
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
       log.info("过滤器开始进行拦截处理了.....");
       // 把 ServletRequest ServletResponse
        // 强转成处理 http协议的对象
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;
        //  把非协议的父类 向下转型成 处理http子类对象 目的用 子类方法
        //  考察知识点  多态.....

        //1:获取到请求的uri /url
        String requestURI = request.getRequestURI();
        log.info("拦截的路径是:"+requestURI);
        // 拦截的路径是:  /backend/page/login/login.html
        // 拦截路径是:  /employee/login
        //2:判断该uri 是不是白名单里面的
        // 一年开发经验的人 会自己个在这里进行判断
        // 两年开发经验的人 一看到判断就定义了一个方法
         boolean isAuth = checkAuthUrl(requestURI);//这个方法来检测 你的uri是不是白名单内容
        //3:如果咱们的 uri是白名单里面的 就放行  不往下走了
        if(isAuth){// 返回的结果是true 说明是白名单
            log.info(requestURI+"是白名单放行");
            chain.doFilter(request, response);
            // 不往下走了
            return;//哥们到这完事了 后面跟我没关系了...
        }
        //4:判断是不是登录了  登录了 放行 不往下走了
        // 加一段代码判断前台用户
        // 去 session中找  登录存的哪个 数据
        Long userId = (Long)request.getSession().getAttribute("user");
        if(userId!=null){//登陆过放行
            log.info("手机端已经登录了放行"+requestURI);
            BaseContext.setCurrentId(userId);

            chain.doFilter(request, response);//放行
            // 不往下走了
            return;//哥们到这完事了 后面跟我没关系了...
        }
        //怎么判断是不是登录?
        // 去 session中找  登录存的哪个 数据
        Long empId = (Long)request.getSession().getAttribute("employee");
       // 这个 empId? 当前用户的id
        // 如果这个数据不为null 登陆了 放行
        if(empId!=null){
            log.info("已经登录了放行"+requestURI);
            // 放行之前 我们要是能够把 这个 empId
            // empId传到.....MyMetaObjectHandler中....
        log.info("当前"+requestURI+" 这个请求的线程id:"+Thread.currentThread().getId());
//           // 把我们empId存到一个ThreadLocal
//           ThreadLocal<Long> threadLocal = BaseContext.instance();
//           threadLocal.set(empId);
            BaseContext.setCurrentId(empId);

            chain.doFilter(request, response);
            // 不往下走了
            return;//哥们到这完事了 后面跟我没关系了...
        }

        //5:没登录告诉 前端 code 0  msg NOTLOGIN
        R notlogin = R.error("NOTLOGIN");
        log.info("该路径被拒签......");
        // 如果不是springmvc开发 怎么给json数据?
        // 通过第三方 json包
        // 1:转换成json
        String jsonString = JSON.toJSONString(notlogin);
        // 2: 通过 输出流写出去
        response.getWriter().write(jsonString);

    }

    /**
     *  两年开发经验的人 设计一个方法
     *     拿到请求路径 跟白名单做对比
     *     目的判断 url是不是在白名单之内
     * @param requestURI
     * @return  如果在白名单  true 不是白名单 false
     */
    public boolean checkAuthUrl(String requestURI) {

      // 创建路径匹配器对象
        AntPathMatcher matcher = new AntPathMatcher();
        // boolean  matcher.match(规则路径,需要匹配的路径)

        // 路径长这样子
        //  /backend/page/login/login.html
        // /employee/login
        // /category/list
        // 白名单数组   也有
        // 你怎么能知道 这个路径 符合不符合  白名单规则
        // 如果感觉的
        for (String url : authUrl) {
            // url 白名单每个规则
            // requestURI 来匹配规则的路径
            // 感觉到判断麻烦  spring框架有没能够实现 路径和规则的匹配
                              //  这样的小技术  有AntPathMatcher
                              // 路径匹配器
//            matcher.match(规则路径,需要匹配的路径)
//            boolean match = matcher.match(url, requestURI);
//            if(match){//如果匹配成功是白名单
//                  return true;
//            }
              // 有开发经验这么写
            if(matcher.match(url,requestURI)){//如果匹配成功是白名单
                return true;
            }
        }

        return false;//如果没有return true 就 return false
    }

    /*
     定义一个白名单数组   有开发经验的人  一年经验
        什么样的拦截
          主要拦截的是后端请求....
     */
    private String[] authUrl = new String[]{
            "/employee/login",
            "/employee/logout",//写不写都行
            "/backend/**", // /backend所有的请求都认定为 白名单
            "/front/**",// /front所有的静态资源 都认定为 白名单
            "/common/**",
            "/user/sendMsg",
            "/user/login"
    };







    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }
}
